/*
 * #%L
 * java model
 * %%
 * Copyright (C) 2009 - 2011 prefabware.com Stefan Isele
 * %%
 * All Rights Reserved.
 * This program is dual-licensed under the GNU General Public license
 * or a commercial license.
 * You may select to use one or the other of these licenses.
 * To obtain a commercial license please contact Stefan Isele at www.stefan-isele.de
 * Any modifications to this file must keep this entire header intact.
 * Redistribution, except as permitted by the selected license, is prohibited.
 * #L%
 */
package com.prefabware.jmodel;

import java.util.ArrayList;
import java.util.List;

import com.prefabware.commons.QualifiedName;
import com.prefabware.jmodel.code.JBlock;
import com.prefabware.jmodel.code.JCodable;
import com.prefabware.jmodel.code.JCodeOptions;
import com.prefabware.jmodel.javadoc.JMethodJavadoc;
import com.prefabware.jmodel.reference.JReference;
import com.prefabware.jmodel.reference.JReferenceBase;

public class JMethod extends JMember implements JCodable,Cloneable {
	/**
	 * @param type
	 * @return the qualifiedName of a constructor of the given type
	 * e.g. type=java.lang.String
	 * returns java.lang.String.String
	 */
	public static QualifiedName getQualifiedName(JType type,String name) {
		QualifiedName qualifiedName = type.getQualifiedName();
		return qualifiedName.append(qualifiedName.getSimpleName());
	};
	private List<JBlock> blocks;
	private List<JThrowable> throwss;

	public boolean add(JBlock e) {
		return blocks.add(e);
	}

	public JMethod(JMethodDeclaration declaration) {
		super(declaration);
	
		this.blocks = new ArrayList<JBlock>();
		this.throwss = new ArrayList<JThrowable>();
		this.javadoc = new JMethodJavadoc();
	}

	public List<JThrowable> getThrows() {
		return throwss;
	}

	public JMethod add(JThrowable exception) {
		throwss.add(exception);
		return this;
	}

	public List<JArgument> getArguments() {
		return getDeclaration().getArguments();
	}

	public JMethodDeclaration getDeclaration() {
		return (JMethodDeclaration) super.getDeclaration();
	}


	public List<JBlock> getBlocks() {
		return blocks;
	}

	/*
	 * returns a shallow copy of this, so at least you can replace the javadoc
	 * without affecting this !
	 */
//	public JMethod copyShallow() {
//		JMethod clone = new JMethod(this.getDeclaration());
//		clone.declaration = this.declaration;
//		clone.throwss = this.throwss;
//		clone.blocks = this.blocks;
//		clone.javadoc = this.javadoc;
//		return clone;
//	}
	
	public JMethod clone() {
		return (JMethod) super.clone();
	}

	@Override
	public String toString() {
		return "JMethod [" + asCode(JCodeOptions.DEFAULT) + "]";
	}

	@Override
	public String asCode(JCodeOptions options) {
		StringBuffer buf = new StringBuffer();
		buf.append(this.getDeclaration().asCode(options));
		return buf.toString();
	}

	public void setDeclaringType(JType jType) {
		this.getDeclaration().setDeclaringType(jType);
	}

	@Override
	public List<JReference<?>> getReferences() {
		List<JReference<?>> references = super.getReferences();
		for (JArgument argument : this.getArguments()) {
			JType argType = argument.getDeclaration().getType();
			references.add(JReferenceBase.create(this.getDeclaringType(),
					argType, argument));
			
			references.addAll(getTypeArgumentReferences(argument));
		}
		return references;
	}
	public List<JReference<?>> getTypeArgumentReferences(JArgument argument) {
		List<JReference<?>> references = new ArrayList<JReference<?>>();
		for (JType refType : argument.getDeclaration().getTypeArguments()) {
			references.add(JReferenceBase.create(this.getDeclaration().getDeclaringType(), refType, refType));
		}
		return references;
	}

}
